﻿using System;
using System.Configuration;
using System.IO;
using System.Reflection;
using MockingBird.Common.Infrastructure.Logging;

namespace MockingBird.Simulator.Framework
{
    using System.Diagnostics;
    using System.Threading;
    using Interfaces;
    using MockingBird.Simulator.Framework.Configuration;

    public class NativeHandlerResolver : IHandlerResolver
    {
        private ApplicationConfiguration appConfig;
        private HandlerMapInfo handlerMapInfo;
        private HandlerRegistrationInfo handlerRegistrationInfo;
        private ILogger logger;
        private string errorMessage;

        public NativeHandlerResolver()
        {
        }

        public NativeHandlerResolver(ApplicationConfiguration appConfiguration, ILogger targetLogger)
        {
            Debug.WriteLine(string.Format("ConfigFileBasedHandlerResolver.ctor on thread ID: {0}", Thread.CurrentThread.ManagedThreadId));
            this.logger = targetLogger;
            this.appConfig = appConfiguration;
        }


        public string GetHandlerNameForEndpoint(string endpoint)
        {
            logger.Log("GetHandlerNameforEndpoint: " + endpoint);

            this.LoadData();

            string handlerName = handlerMapInfo.GetHandlerNameForEndpoint(endpoint);
            //if there is no handler for the endpoint then throw an exception
            if (String.IsNullOrEmpty(handlerName))
            {
                this.errorMessage = String.Format("Request Handler not available for endpoint : {0}. Check that the full endpoint including file extension (especially for ASMX) is specified in the HandlerMap section. For  ", endpoint);
                this.logger.Log(this.errorMessage);
                this.DumpHandlerMapEntries();
                throw new ConfigurationErrorsException(this.errorMessage);
            }

            return handlerName;

        }

        public Type GetHandlerType(string handlerName)
        {
            this.logger.Log("GetHandlerType");
            // In case the data hasnt been loaded
            this.LoadData();

            //Get the handler type name from the registration info structure and throw an exception 
            //if we cant find anything registered
            string handlerFullTypeName = handlerRegistrationInfo.GetHandlerTypeName(handlerName);

            if (String.IsNullOrEmpty(handlerFullTypeName))
            {
                this.errorMessage = "could not find a registered type for the specified handler name :" + handlerName;
                this.logger.Log(this.errorMessage);
                this.DumpHandlerRegEntries();
                throw new ConfigurationErrorsException(this.errorMessage);
            }


            return CreateAndReturnType(handlerFullTypeName);

        }

        private void LoadData()
        {
            this.logger.Log("LoadData");
            this.handlerMapInfo = this.appConfig.GetHandlerMapInfo();
            this.handlerRegistrationInfo = this.appConfig.GetHandlerRegistrationInfo();
            this.ValidateConfiguration();
        }

        private void ValidateConfiguration()
        {
            this.logger.Log("ValidateConfiguration");
            //this may still be null
            if ((this.handlerMapInfo == null) || (this.handlerMapInfo.IsEmpty))
            {
                throw new InvalidDataException("HandlerMapInfo is Empty Or Null.Cannot proceed");
            }

            if ((this.handlerRegistrationInfo == null) || (this.handlerRegistrationInfo.IsEmpty))
            {
                throw new InvalidDataException("HandlerRegistrationInfo is Empty Or Null.Cannot proceed");
            }
        }


        private Type CreateAndReturnType(string handlerFullTypeName)
        {
            this.logger.Log("CreateAndReturnType");
            //Now parse the type name to get the assembly name and the short type name
            string handlerAssemblyName = handlerFullTypeName.Split(",".ToCharArray())[1];
            string handlerShortTypeName = handlerFullTypeName.Split(",".ToCharArray())[0];

            //Create an appropriate type from the assembly and return it
            var handlerAsssembly = Assembly.Load(handlerAssemblyName);
            Type handlerType = handlerAsssembly.GetType(handlerShortTypeName);

            return handlerType;

        }

        private void DumpHandlerMapEntries()
        {
            this.logger.Log(this.handlerMapInfo.Serialize());
        }

        private void DumpHandlerRegEntries()
        {
            this.logger.Log(this.handlerRegistrationInfo.Serialize());
        }


    }
}
